
function remove(arr, item) {
  if(arr.length) {
    const ind = arr.indexOf(item)
    if (ind > -1) {
      return arr.splice(ind, 1)
    } 
  }
}
class Dep {
  constructor() {
    this.subs = []
  }
  addSub(sub) {
    this.subs.push(sub)
  }
  removeSub(sub) {
    remove(this.subs, sub)
  }
  depend() {
    if (window.target) { // 找一个全局的位置
      this.addSub(window.target)
    }
  }
  notify() {
    const subs = this.subs.slice()
    for (let i = 0, l = subs.length; i < l; i++) {
      subs[i].update()
    }
  }
}

function observe(value, asRootData) {
  if (!isObject(value)) {
    return
  }
  let ob
  if (hasOwn(value, '__ob__') && value.__ob__ instanceof Observer) {
    ob = value.__ob__
  } else {
    ob = new Observer(value)
  }
  return ob
}
function isObject(v) {
  return Object.prototype.toString.call(v) === '[object Object]'
}
function hasOwn(target, attr) {
  return Object.hasOwnProperty.call(target, attr)
}

function defineReactive(data, key, val) {
  // if (typeof val === 'object') new Observer(val) // 递归设置对象的属性为可侦测
  let childOb = observe(val)
  let dep = new Dep()
  Object.defineProperty(data, key, {
    enumerable: true,
    configurable: true,
    get: function() {
      // console.log('defineReactive get')
      dep.depend()
      if (childOb) {
        childOb.dep.depend()
        dep.depend()
      }
      return val
    },
    set: function(newVal) {
      // console.log('defineReactive set')
      if (val === newVal) {
        return
      }
      val = newVal
      dep.notify()
    }
  })
}

class Watcher {
  constructor(vm, expOrFn, cb) {
    this.vm = vm
    this.getter = parsePath(expOrFn)
    this.cb = cb
    this.value = this.get()
  }
  get() {
    window.target = this
    let value = this.getter.call(this.vm, this.vm) // 将自己添加到自动添加到Dep中去
    window.target = undefined
    return value
  }
  update() {
    const oldVal = this.value
    this.value = this.get()
    this.cb.call(this.vm, this.value, oldVal)
  }
}

const bailRE = /[^\w.$]/
function parsePath(path) {
  if (bailRE.test(path)) {
    return
  }
  const segments = path.split('.')
  return function(obj) {
    for (let i=0;i<segments.length;i++) {
      if (!obj) return
      obj = obj[segments[i]]
    }
    return obj
  }
}

// Array原型方法的重新定义，并只应用于需要响应式的数组上
const arrayProto = Array.prototype
const arrayMethods = Object.create(arrayProto);
[
  'push',
  'pop',
  'shift',
  'unshift',
  'splice',
  'sort',
  'reverse'
].forEach(function(method) {
  const original = arrayProto[method]
  Object.defineProperty(arrayMethods, method, {
    enumerable: false,
    configurable: true,
    writable: true,
    value: function mutator(...args) {
      // pre do something else
      return original.apply(this,...args)
    }
  })
})

const hasProto = '__proto__' in {}
const arrayKeys = Object.getOwnPropertyNames(arrayMethods)

function protoAugment(target, src, keys) {
  target.__proto__ = src
}
function copyAugment(target, src, keys) {
  for(let i=0; i<keys.length; i++) {
    const key = keys[i]
    // def(target, key, src[key])
    target[key] = src[key]
  }
}
class Observer {
  constructor (value) {
    this.value = value
    this.dep = new Dep()
    if (Array.isArray(value)) {
      const augment = hasProto ? protoAugment : copyAugment
      augment(value, arrayMethods, arrayKeys)
    }else {
      this.walk(value)
    }
  }
  walk (obj) {
    const keys = Object.keys(obj)
    for (let i = 0; i < keys.length; i++) {
      defineReactive(obj, keys[i], obj[keys[i]])
    }
  }
}

// test 
let testObj = {
  a: 'a',
  b: 'b',
  c: {
    cc: 'cc',
    dd: 'dd',
    ee: {
      fff: 'fff',
      ggg: 'ggg'
    },
    ff: [
      1, 2, 3
    ]
  }
}

const testObjIns = new Observer(testObj)
// // const aAttr = testObj.a
// // const aAttr2 = testObj.a
// testObj.c.ee.fff = 'test c.ee.fff '


console.log(isObject({}));
